package org.shadow.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.shadow.common.util.StringUtils;
import org.shadow.process.HttpRequestProcess;
import org.shadow.process.HttpResponseProcess;

public class HttpServer {
	private Logger logger = LogManager.getLogger();
	private Selector selector;
	private ServerSocketChannel serverSocketChannel;

	private String addr;

	private int port;

	public HttpServer setAddr(String addr) {
		this.addr = addr;
		return this;
	}

	public HttpServer setPort(int port) {
		this.port = port;
		return this;
	}

	public HttpServer build() {
		logger.info("HttpServer Init addr is:{},port is:{}", addr, port);
		try {

			if (StringUtils.isEmpty(addr)) {
				logger.info("HttpServer Init error addr is null");
				return null;
			}
			if (port < 1024) {
				logger.info("HttpServer Init error port error");
				return null;
			}
			selector = Selector.open();
			serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.configureBlocking(false);
			serverSocketChannel.socket().bind(new InetSocketAddress(addr, port));
			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		} catch (IOException e) {
			e.printStackTrace();
		}

		return this;
	}

	public void start() {
		logger.info("HttpServer start");
		try {
			while (selector.select() > 0) {
				Set<SelectionKey> selectionKeys = selector.selectedKeys();
				Iterator<SelectionKey> iterator = selectionKeys.iterator();
				while (iterator.hasNext()) {
					SelectionKey key = iterator.next();
					iterator.remove();
					if (key.isAcceptable()) {
						ServerSocketChannel channel = (ServerSocketChannel) key.channel();
						SocketChannel readChannel = channel.accept();
						if (readChannel != null) {
							readChannel.configureBlocking(false);
							readChannel.register(selector, SelectionKey.OP_READ);
						}
					} else if (key.isReadable()) {
						HttpRequestProcess requestProcess = new HttpRequestProcess();
						requestProcess.process(key, selector);
						key.interestOps(SelectionKey.OP_WRITE);
					} else if (key.isWritable()) {
						HttpResponseProcess responseProcess = new HttpResponseProcess();
						responseProcess.process(key);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
